/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package simhya;
import simhya.simengine.stochastic.jep.*;
import simhya.model.store.faststore.*;
import simhya.model.store.*;
import java.util.*;
import simhya.simengine.*;
import simhya.dataprocessing.*;
import simhya.simengine.stochastic.*;
import simhya.model.stochastic.*;
import simhya.model.transition.*;
import simhya.utils.*;
import cern.jet.random.engine.RandomEngine;
import org.nfunk.jep.Variable;
import org.nfunk.jep.JEP;
import org.nfunk.jep.Node;

import simhya.matheval.*;



/**
 *
 * @author Luca
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {


//        test();
        simulateModel();
//       testParser();

        
    }

private static void simulateModel(){
    Debugger.activate();
    double finalTime = 50000;
    int points = 1000;
    double delta = finalTime/points;
    Examples ex = new Examples();
    StochasticSimulator sim;
    StochasticModel model;

    SingleStochasticTrajectoryCollector dc = new SingleStochasticTrajectoryCollector(delta);
    //StochasticModel model = ex.randomWalkWithBarrierAndScheduledReset(10,100.0);
    //StochasticModel model = ex.SIRtwoRecoveryRatesHisteresis(1000, 2.0, 0.5, 5.0, 0.1, 0.4, 0.2);
    model = ex.SIR(1000, 1.0, 1.5, 0.1);
    //model = ex.SIReval(1000, 1.0, 1.5, 0.1,true);
    //model = ex.SIReval(1000, 1.0, 1.5, 0.1,false);
    //StochasticModel model = ex.ProstateCancer(1000, true, false, false, false);

    dc.setVariablesHeader(model.getNameOfAllVariables());
    //sim = new simhya.simengine.stochastic.jep.old.SSASimulator(model,dc);
    //sim = new SSASimulator(model,dc);
    sim = new simhya.simengine.stochastic.fast.SSASimulator(model,dc);
    //sim = new simhya.simengine.stochastic.fast.PureSSASimulator(model,dc);
    //((simhya.simengine.stochastic.fast.PureSSASimulator)sim).setUseDependencyGraph(false);

    sim.setFinalTime(finalTime);
    sim.initialize();
    sim.run();
    
    Trajectory tr  =  dc.getTrajectory();
    tr.toScreen();
    System.out.println("Simulation time " + String.format(Locale.US, "%.4f", sim.getLastSimulationTime()) + " milliseconds ");
    System.out.println("Steps of simulation: " + sim.getLastSimulationSteps());
    System.out.println("Stochastic steps: " + sim.getLastSimulationStochasticSteps());
    System.out.println("Instantaneous steps: " + sim.getLastSimulationInstantaneousSteps());
    System.out.println("Timed steps: " + sim.getLastSimulationTimedSteps());
    System.out.println("Delayed steps: " + sim.getLastSimulationDelayedSteps());
    System.out.println("Average time per step: " + String.format(Locale.US, "%.4f", sim.getLastSimulationTime()/sim.getLastSimulationSteps()) + " milliseconds ");

}


private static void test() {
    
    int reps = 10000000;

    String expression = "k*Y + X";

    JEP jep = new JEP();
    jep.addVariable("X", 4.0);
    jep.addVariable("Y", 2.0);
    jep.addConstant("k", 5.0);
    Node jepNode = null;
    try {jepNode = jep.parse(expression); } catch (Exception e) {e.printStackTrace();}

    Evaluator eval = new Evaluator();
    eval.addVariable("X", 4.0);
    eval.addVariable("Y", 2.0);
    eval.addConstant("k", 5.0);
    int id = -1;
    try {id = eval.parse(expression); } catch (Exception e) { e.printStackTrace();}
    Expression exp = eval.getExpression(id);
    
    double x;
    double[] V = new double[2];
    double[] P = new double[1];

    SymbolArray array = new SymbolArray();
    array.addSymbol("X", 6.0);
    array.addSymbol("Y", 1.0);

    int ec = eval.newEvaluationCode();
   
    long time = System.nanoTime();
    for (int i=0;i<reps;i++) {
       //try { x = (Double)jep.evaluate(jepNode); }  catch (Exception e) {e.printStackTrace();}
       x = exp.computeValue();
       //x = exp.computeValue(array);
       //x = exp.computeValue(ec);
       //x = exp.computeValue(array,ec);
       //x = P[0]*V[1] + V[0];
    }
    time = System.nanoTime() - time;
    double t = (double)time / 1000000;
    System.out.println("Total time: " + t + " milliseconds ");
    System.out.println("Time per step: " + t/reps + " milliseconds ");


}
    
private static void testParser() {
    Evaluator eval = new Evaluator();
    eval.addVariable("X", 2.0);
    eval.addVariable("Y", 6.5);
    eval.addConstant("k", 16.0);
    int id = -1;
    try {
        eval.parse("ciccio(X) := (X > 0)*k");
        //id = eval.parse("ciccio(Y)");
        id = eval.parse("sqrt(ciccio(Y))");
    } catch (Exception e) { e.printStackTrace();}
    Expression exp = eval.getExpression(id);
    System.out.println(exp);
    double x = exp.computeValue();
    System.out.println("Value is " + x);
}


}

class Wrapper {
    double [] v;
    int n;

    public Wrapper(int n) {
        this.n = n;
        v = new double[n];
    }


    public void set(int k, double x) {
//        if (k < 0 || k >= n)
//            throw new RuntimeException("Sticazzi");
        v[k] = x;
    }

    public double get(int k) {
//        if (k < 0 || k >= n)
//            throw new RuntimeException("Sticazzi");
        return v[k];
    }




}



class Plus {
    public double compute(double x1, double x2) {
        return x1 + x2;
    }
}

 class Times {
    public double compute(double x1, double x2) {
        return x1 + x2;
    }
}